package com.atguigu.gmall.seckill.listener;
import java.math.BigDecimal;

import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.google.common.collect.Lists;

import java.util.ArrayList;
import java.util.Date;
import com.atguigu.gmall.model.activity.CouponInfo;

import com.atguigu.gmall.common.constans.MqConstant;
import com.atguigu.gmall.common.constans.RedisConstant;
import com.atguigu.gmall.common.util.JsonUtil;
import com.atguigu.gmall.model.activity.SeckillGoods;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.model.to.SecKillQueueTo;
import com.atguigu.gmall.seckill.firstcache.SeckillFirstcache;
import com.atguigu.gmall.seckill.service.SeckillGoodsService;
import com.fasterxml.jackson.core.type.TypeReference;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author A
 * @version 1.0
 * @description: TODO
 * @date 2025/9/19 1:49
 */
@Slf4j
@Component
public class SeckillOrderListener {
    @Autowired
    SeckillGoodsService seckillGoodsService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    SeckillFirstcache seckillFirstcache;
    @RabbitListener(bindings =@QueueBinding(
            exchange = @Exchange(value = MqConstant.SECKILL_ORDER_EXCHANGE,type = "topic",durable = "true"),
            value = @Queue(value = MqConstant.SECKILL_ORDER_QUEUE,durable = "true",autoDelete = "false",exclusive = "false",declare = "true"),
            key = MqConstant.SECKILL_ORDER_ROUTING_KEY
    ))
    public void receiveSeckillOrder(Message message, Channel channel){
        String msg = new String(message.getBody());
        SecKillQueueTo secKillQueueTo = JsonUtil.jsonToObject(msg, new TypeReference<SecKillQueueTo>() {
        });
        Long userId = secKillQueueTo.getUserId();
        Long skuId = secKillQueueTo.getSkuId();
        String dateStr = secKillQueueTo.getDateStr();
        try {
            //保存订单信息到redis,减数据库库存
            reduceStockAndSaveOrder(secKillQueueTo);
            log.info("{}:扣减库存成功,开始临时创建订单",skuId);
        } catch (Exception e) {
           //表示库存减少失败,秒杀抢单失败,给redis中存放失败的临时订单信息
            String key = RedisConstant.SECKILL_ORDER_PREFIX + userId + ":" + dateStr + ":" + skuId;
            stringRedisTemplate.opsForValue().set(key,"boom",2, TimeUnit.DAYS);
            log.info("{}:库存减少失败,秒杀抢单失败,保存临时订单信息到redis",skuId);
        }
        try {
            log.info("成功监听到排队的消息:{}",msg);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    @Transactional
    public void reduceStockAndSaveOrder(SecKillQueueTo secKillQueueTo) {
        //减库存
        seckillGoodsService.reduceStock(secKillQueueTo);
        //保存临时订单信息到redis
        OrderInfo orderInfo =prepareOrderInfo(secKillQueueTo);
        String key = RedisConstant.SECKILL_ORDER_PREFIX + secKillQueueTo.getUserId() + ":" + secKillQueueTo.getDateStr() + ":" + secKillQueueTo.getSkuId();
        stringRedisTemplate.opsForValue().set(key, JsonUtil.toStr(orderInfo), 2, TimeUnit.DAYS);

    }

    private OrderInfo prepareOrderInfo(SecKillQueueTo secKillQueueTo) {
        Long skuId = secKillQueueTo.getSkuId();
        Long userId = secKillQueueTo.getUserId();
        SeckillGoods seckillGoods = seckillFirstcache.getSeckillCache(skuId);
        String unpaidStatus = ProcessStatus.UNPAID.name();

        OrderInfo orderInfo = new OrderInfo();

        orderInfo.setTotalAmount(seckillGoods.getCostPrice());
        orderInfo.setOrderStatus(unpaidStatus);
        orderInfo.setUserId(userId);
        orderInfo.setPaymentWay("2");
        orderInfo.setTradeBody(seckillGoods.getSkuName());
        orderInfo.setCreateTime(new Date());
        long expireTime = System.currentTimeMillis() + 1000 * 60 * 30;
        orderInfo.setExpireTime(new Date(expireTime));
        orderInfo.setProcessStatus(unpaidStatus);

        orderInfo.setParentOrderId(0L);
        orderInfo.setImgUrl(seckillGoods.getSkuDefaultImg());
        List<OrderDetail> orderDetailList =prepareOrderDetailList(orderInfo, seckillGoods);
        orderInfo.setOrderDetailList(orderDetailList);

        orderInfo.setOriginalTotalAmount(seckillGoods.getPrice());
        return orderInfo;
    }

    private List<OrderDetail> prepareOrderDetailList(OrderInfo orderInfo, SeckillGoods seckillGoods) {

        OrderDetail orderDetail = new OrderDetail();

        orderDetail.setUserId(orderInfo.getUserId());
        orderDetail.setSkuId(seckillGoods.getId());
        orderDetail.setSkuName(seckillGoods.getSkuName());
        orderDetail.setImgUrl(seckillGoods.getSkuDefaultImg());
        orderDetail.setOrderPrice(seckillGoods.getCostPrice());
        orderDetail.setSkuNum(1);

        orderDetail.setCreateTime(new Date());
        orderDetail.setSplitTotalAmount(seckillGoods.getCostPrice());

        return Lists.newArrayList(orderDetail);
    }
}
